package idgenerator

import "strconv"

//redis command(GET key) -> value
func (s *IdGenService) handleGet(r *Request) Reply {
	var gen IdGenerator
	var ok bool
	var id int64

	if r.HasArgument(0) == false {
		return ErrNotEnoughArgs
	}

	idGenKey := string(r.Arguments[0])
	if len(idGenKey) == 0 {
		return ErrNoKey
	}

	s.Lock()
	gen, ok = s.keyGeneratorMap[idGenKey]

	if ok == false {
		s.Unlock()
		return &EmptyReply{}
	}
	s.Unlock()

	if gen.GetCurrentId() == 0 && gen.GetBatchMax() == 0 {
		_ = gen.Init()
	}

	id = gen.GetCurrentId()

	return &IntReply{
		number: id,
	}
}

//redis command(INCR key) -> value+1
func (s *IdGenService) handleIncr(r *Request) Reply {
	var gen IdGenerator
	var ok bool
	var id int64
	var err error

	if r.HasArgument(0) == false {
		return ErrNotEnoughArgs
	}

	idGenKey := string(r.Arguments[0])
	if len(idGenKey) == 0 {
		return ErrNoKey
	}

	s.Lock()
	gen, ok = s.keyGeneratorMap[idGenKey]
	if ok == false {
		s.Unlock()
		return &BulkReply{
			value: nil,
		}
	}
	s.Unlock()

	id, err = gen.Next()
	if err != nil {
		return &ErrorReply{
			message: err.Error(),
		}
	}
	if id == 0 {
		return &ErrorReply{
			message: ErrExpectEvenPair.Error(),
		}
	}

	return &IntReply{
		number: id,
	}
}

//redis command(SET key value) -> OK
func (s *IdGenService) handleSet(r *Request) Reply {
	var gen IdGenerator
	var ok bool
	var err error

	if r.HasArgument(0) == false {
		return ErrNotEnoughArgs
	}

	idGenKey := string(r.Arguments[0])
	if len(idGenKey) == 0 {
		return ErrNoKey
	}
	var id int64 = 0
	idStr := string(r.Arguments[1])
	if len(idStr) > 0 {
		_id, e := strconv.ParseInt(idStr, 10, 64)
		if e == nil {
			id = _id
		}
	}

	s.Lock()
	gen, ok = s.keyGeneratorMap[idGenKey]
	if ok == false {
		gen, err = NewIdGenerator(s.db, idGenKey)
		if err != nil {
			s.Unlock()
			return &ErrorReply{
				message: err.Error(),
			}
		}
		s.keyGeneratorMap[idGenKey] = gen
	}
	gen.SetCurrentId(id)
	gen.SetBatchMax(id + gen.GetBatchMax())
	err = s.setKey(idGenKey, gen.GetBatchMax())
	if err != nil {
		return &ErrorReply{
			message: err.Error(),
		}
	}
	s.Unlock()

	return &StatusReply{
		code: "OK",
	}
}

//redis command(EXISTS key [key ...]) -> 1 OR 0
func (s *IdGenService) handleExists(r *Request) Reply {
	var ok bool
	var id int64

	if r.HasArgument(0) == false {
		return ErrNotEnoughArgs
	}

	idGenKey := string(r.Arguments[0])
	if len(idGenKey) == 0 {
		return ErrNoKey
	}

	s.Lock()
	_, ok = s.keyGeneratorMap[idGenKey]
	s.Unlock()

	if ok {
		id = 1
	}

	return &IntReply{
		number: id,
	}
}

//redis command(DEL key [key ...]) -> 1
func (s *IdGenService) handleDel(r *Request) Reply {
	var ok bool
	var id int64 = 0

	if r.HasArgument(0) == false {
		return ErrNotEnoughArgs
	}

	idGenKey := string(r.Arguments[0])
	if len(idGenKey) == 0 {
		return ErrNoKey
	}

	s.Lock()
	_, ok = s.keyGeneratorMap[idGenKey]
	if ok {
		delete(s.keyGeneratorMap, idGenKey)
	}

	if ok {
		err := s.delKey(idGenKey)
		if err != nil {
			s.Unlock()
			return &ErrorReply{
				message: err.Error(),
			}
		}
		id = 1
	}
	s.Unlock()

	return &IntReply{
		number: id,
	}
}

//redis command(SELECT 1) -> OK
func (s *IdGenService) handleSelect(r *Request) Reply {
	if r.HasArgument(0) == false {
		return ErrNotEnoughArgs
	}

	num := string(r.Arguments[0])
	if len(num) == 0 {
		return ErrNotEnoughArgs
	}

	return &StatusReply{
		code: "OK",
	}
}

//redis command(AUTH <password>) -> OK
func (s *IdGenService) handleAuth(r *Request) Reply {
	if len(s.password) > 0 {
		if r.HasArgument(0) == false {
			return ErrExpectAuth
		}
		password := string(r.Arguments[0])
		if len(password) == 0 {
			return ErrExpectAuth
		}
		if password != s.password {
			return ErrExpectAuth
		}
	}
	return &StatusReply{
		code: "OK",
	}
}

//redis command(PING [message]) -> PONG
func (s *IdGenService) handlePing(r *Request) Reply {
	if r.HasArgument(0) == false {
		return &PongReply{}
	}

	msg := string(r.Arguments[0])
	if len(msg) > 0 {
		return &StatusReply{
			code: msg,
		}
	}
	return &PongReply{}
}

//redis command(QUIT) -> OK
func (s *IdGenService) handleQuit(_ *Request) Reply {
	return &StatusReply{
		code: "OK",
	}
}

//redis command(SHUTDOWN [NOSAVE|SAVE]) -> OK
func (s *IdGenService) handleShutdown(_ *Request) Reply {
	s.Lock()
	s.running = false
	_ = s.listener.Close()
	s.Unlock()
	return &StatusReply{
		code: "OK",
	}
}
